package bearworker.zxl.utils;

import bearworker.zxl.dao.mapper.WxAccessTokenMapper;
import bearworker.zxl.dao.mapper.WxUserTicketMapper;
import bearworker.zxl.entity.DeliveryWxpayRecords;
import bearworker.zxl.entity.StaticDataEntity;
import bearworker.zxl.entity.WxAccessToken;
import bearworker.zxl.entity.WxUserTicket;
import bearworker.zxl.entity.extra.WxPayEntity;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * Created by 逍遥的熊 on 2018/1/10.
 */
@Component
public class WxUtil {

    private static Logger logger = Logger.getLogger(WxUtil.class);

    private static StaticDataEntity staticData =(StaticDataEntity) SpringContext.getBean("staticData");

    @Autowired
    private WxAccessTokenMapper tokenMapper;

    @Autowired
    private WxUserTicketMapper ticketMapper;

    private static WxUtil wxUtil;

    private static Gson gson = new Gson();

    @PostConstruct
    public void init(){
        wxUtil = this;
        wxUtil.tokenMapper = this.tokenMapper;
        wxUtil.ticketMapper = this.ticketMapper;
    }


    public static void analyzeWxMsg(Map dataMap){
        String msgType = (String) dataMap.get("MsgType");

        switch (msgType){
            case "text":
                break;
            default:
                logger.debug("no msgType:"+msgType);
                break;
        }
    }

    private static String getAccessToken(){

        Map<String,String> tokenMap = RedisUtil.get("accessToken");

        if(StringUtils.isNotEmpty(tokenMap.get("accessToken"))){
            return tokenMap.get("accessToken");
        }else {
            WxAccessToken accessToken = wxUtil.tokenMapper.selectByPrimaryKey();

            if (accessToken != null && accessToken.getId() != null && accessToken.getId() > 0){
                return accessToken.getAccessToken();
            }else {

                accessToken = new WxAccessToken();

                String url = staticData.getWxReqUrl() + "/cgi-bin/token";
                String param = String.format("grant_type=client_credential&appid=%s&secret=%s", staticData.getAppId(), staticData.getSecret());
                String result = RequestUtil.sendGet(url, param);

                logger.debug(result);

                Map<String,Object> accTMap = gson.fromJson(result, Map.class);

                if(accTMap.containsKey("access_token")) {
                    accessToken.setAccessToken((String) accTMap.get("access_token"));
                    accessToken.setExpiresIn(((Double) accTMap.get("expires_in")).intValue());

                    RedisUtil.set("accessToken", accessToken.getAccessToken());
                    RedisUtil.setExp("accessToken", accessToken.getExpiresIn().longValue());

                    wxUtil.tokenMapper.insertSelective(accessToken);

                    return accessToken.getAccessToken();
                }else {
                    logger.error(accTMap.get("errcode")+":"+ErrorMsgUtil.wxErrMsg(((Double) accTMap.get("errcode")).intValue()));
                    return "";
                }
            }
        }
    }

    public static DeliveryWxpayRecords wxPay(String ordType,String prodDesc,String orderNo,Integer totalFee,String openId){
        Map<String,Object> payMap = new HashMap<>();
        WxPayEntity payEntity = new WxPayEntity();
        DeliveryWxpayRecords records = new DeliveryWxpayRecords();
        Map<String,Object> jsMap = new HashMap<>();
        String nonceStr = RandomStringUtils.randomAlphanumeric(32);
        switch (ordType){
            case "wx":

                break;
            case "pro":
                payMap.put("appid",staticData.getProAppId());
                payMap.put("mch_id",staticData.getMchId());
                payMap.put("nonce_str",nonceStr);
                payMap.put("body",prodDesc);
                payMap.put("out_trade_no",orderNo);
                payMap.put("total_fee",totalFee);
                payMap.put("spbill_create_ip","172.19.182.204");
                payMap.put("notify_url",staticData.getProNotifyUrl());
                payMap.put("trade_type","JSAPI");
                payMap.put("openid",openId);

                String cryptoStr = payCrypto(payMap,staticData.getPayKey());
                payMap.put("sign",cryptoStr);

                break;
            default:
                logger.debug("无对应交易方法");

        }

        payEntity.setAppid(payMap.get("appid").toString());
        payEntity.setMch_id(payMap.get("mch_id").toString());
        payEntity.setNonce_str(payMap.get("nonce_str").toString());
        payEntity.setBody(payMap.get("body").toString());
        payEntity.setOut_trade_no(payMap.get("out_trade_no").toString());
        payEntity.setTotal_fee(Integer.valueOf(payMap.get("total_fee").toString()));
        payEntity.setSpbill_create_ip(payMap.get("spbill_create_ip").toString());
        payEntity.setNotify_url(payMap.get("notify_url").toString());
        payEntity.setTrade_type(payMap.get("trade_type").toString());
        payEntity.setOpenid(payMap.get("openid").toString());
        payEntity.setSign(payMap.get("sign").toString());

        String xmlData = XmlUtil.mapToXml(payEntity);
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        String res = RequestUtil.sendPost(url,xmlData);
        logger.debug(res);
        Map<String,String> resMap = XmlUtil.xmltoMap(res);

        records.setAppid(payEntity.getAppid());
        records.setMchId(payEntity.getMch_id());
        records.setNonceStr(payEntity.getNonce_str());
        records.setBody(payEntity.getBody());
        records.setOutTradeNo(payEntity.getOut_trade_no());
        records.setTotalFee(payEntity.getTotal_fee());
        records.setSpbillCreateIp(payEntity.getSpbill_create_ip());
        records.setNotifyUrl(payEntity.getNotify_url());
        records.setTradeType(payEntity.getTrade_type());
        records.setOpenid(payEntity.getOpenid());
        records.setSign(payEntity.getSign());
        records.setResAppid(resMap.get("appid"));
        records.setResMchId(resMap.get("mch_id"));
        records.setResNonceStr(resMap.get("nonce_str"));
        records.setResPrepayId(resMap.get("prepay_id"));
        records.setResResultCode(resMap.get("return_code"));
        records.setResReturnCode(resMap.get("result_code"));
        records.setResReturnMsg(resMap.get("return_msg"));
        records.setResSign(resMap.get("sign"));
        records.setResTradeType(resMap.get("trade_type"));

        jsMap.put("appId",records.getAppid());
        jsMap.put("timeStamp",new Date().getTime()/1000+"");
        jsMap.put("nonceStr",records.getNonceStr());
        jsMap.put("package","prepay_id="+records.getResPrepayId());
        jsMap.put("signType","MD5");


        String jsCryptoStr = payCrypto(jsMap,staticData.getPayKey());
        records.setJsTimestamp(jsMap.get("timeStamp").toString());
        records.setJsSigntype(jsMap.get("signType").toString());
        records.setJsPackage(jsMap.get("package").toString());
        records.setJsSign(jsCryptoStr);

        return records;
    }

    public static Map<String,String> proGetSession(String code){
        Map<String,String> resMap = new HashMap<>();
        String appId = staticData.getProAppId();
        String secret = staticData.getProAppSecret();
        String grantType = "authorization_code";

        String url = "https://api.weixin.qq.com/sns/jscode2session";
        String param = "appid="+appId+"&secret="+secret+"&js_code="+code+"&grant_type="+grantType;
        String resultStr = RequestUtil.sendGet(url,param);
        logger.info("resultStr:"+resultStr);

        JSONObject resultJsonObject = JSONObject.parseObject(resultStr);

        String openId = resultJsonObject.getString("openid");
        String unionId = resultJsonObject.containsKey("unionid") ? resultJsonObject.getString("unionid") : "";
        String sessionKey = resultJsonObject.getString("session_key");

        resMap.put("openId",openId);
        resMap.put("unionId",unionId);
        resMap.put("sessionKey",sessionKey);

        return resMap;
    }

    private static String payCrypto(Map<String,Object> data,String secret){

        StringBuffer parmStr = new StringBuffer("");

        Map<String, Object> sortMap = new TreeMap<String, Object>(
                new Comparator<String>() {
                    public int compare(String obj1, String obj2) {
                        // 升序排序
                        return obj1.compareTo(obj2);
                    }
                }
        );

        sortMap.putAll(data);

        Iterator<String> iter = sortMap.keySet().iterator();
        while (iter.hasNext()){
            String key = iter.next();
            if(parmStr.toString().equals("")){
                parmStr.append(key+"="+sortMap.get(key));
            }
            else{
                parmStr.append("&"+key+"="+sortMap.get(key));
            }
        }
        parmStr.append("&key="+secret);

        String sourceStr = parmStr.toString();

        String cryptoStr = CryptoUtil.MD5(sourceStr).toUpperCase();

        logger.debug("source:"+sourceStr);
        logger.debug("crypto:"+cryptoStr);

        return cryptoStr;
    }

    public static String userShareUrl(String openId,String sceneStr){
        WxUserTicket ticket = wxUtil.ticketMapper.selectByOpenId(openId);

        if(ticket != null){
            return ticket.getTicket();
        }else {
            ticket = new WxUserTicket();

            String token = getAccessToken();
            Map<String, Object> paramMap = new HashMap<>();
            Map<String, Object> paramsMap = new HashMap<>();
            Map<String, Object> paramdMap = new HashMap<>();

            paramdMap.put("scene_str", sceneStr);

            paramsMap.put("scene", paramdMap);

            paramMap.put("expire_seconds", 2592000);
            paramMap.put("action_name", "QR_LIMIT_STR_SCENE");
            paramMap.put("action_info", paramsMap);

            String paramStr = gson.toJson(paramMap);

            String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + token;

            String resStr = RequestUtil.sendPost(url, paramStr);

            logger.debug(resStr);

            Map<String, Object> resMap = gson.fromJson(resStr, HashMap.class);

            long currentTime = System.currentTimeMillis();

            ticket.setOpenId(openId);
            ticket.setSceneStr(sceneStr);
            ticket.setTicket(resMap.get("ticket").toString());
            ticket.setExpireTime(new Date(currentTime + 2592000));

            wxUtil.ticketMapper.insert(ticket);

            return resMap.get("ticket").toString();
        }
    }
}
